package com.solidtrust.crawlers;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.solidtrust.crawler.framework.BaseSitemap;
import com.solidtrust.crawler.framework.IUrlOverrider;
import com.solidtrust.crawler.model.PageSource;
import com.solidtrust.entity.IScrapeEntity;
import com.solidtrust.entity.Renrenche;
import com.solidtrust.util.DateUtil;
import com.solidtrust.util.HttpUtil;

@Service
public class RenrencheSitemap extends BaseSitemap{
	private static final Logger log4j = Logger.getLogger(RenrencheSitemap.class);
	private static final String BRAND_MODEL_API_URL = "https://www.renrenche.com/index.php?d=api&c=search_cars_info&car_info_city={0}&not_open_city=0";
	private ObjectMapper om = new ObjectMapper();
	
	@Override
	public String getStartUrl() {
		return "https://www.renrenche.com/";
	}

	@Override
	public List<PageSource> getCitiesOrProvinces(Document doc) {
		List<PageSource> list = new ArrayList<>();
		Elements eles = doc.select("#cities a.province-item");
		IUrlOverrider io = (String url) -> {
			return url + "/ershouche";
		};
		for (int i = 0; i < eles.size(); i++) {
			PageSource c = new PageSource();
			c.setUrl(eles.get(i).attr("abs:href"));
			c.setName(eles.get(i).text());
			c.setUrlOverrider(io);
			c.setId(eles.get(i).attr("rrc-event-name"));
			log4j.info(c);
			if(c.getId().equals("bj")){
				continue;
			}
			list.add(c);
		}
		return list;
	}
	
	
	private String getPageUrl(String brand, String city){
		return "https://www.renrenche.com/"+city+"/"+brand;
	}
	
	@Override
	public List<PageSource> getBrands(Document doc, PageSource c) {
		List<PageSource> list = new ArrayList<>();
		String s = MessageFormat.format(BRAND_MODEL_API_URL, c.getName());
		InputStream in = null;
		try{
			URL url = new URL(s);
			HttpURLConnection conn = (HttpURLConnection)url.openConnection();
			HttpUtil.addHttpHeads(conn);
			in = new GZIPInputStream(conn.getInputStream());
			String result = IOUtils.toString(in);
			ArrayNode array = (ArrayNode)(om.readTree(result)).get("data");
			for (int i = 0; i < array.size(); i++) {
				JsonNode n = array.get(i);
				PageSource brand = new PageSource();
				brand.setId(n.get("b_pinyin").asText());
				brand.setUrl(getPageUrl(brand.getId(), c.getId()));
				brand.setName(n.get("brand_name").asText());
				list.add(brand);
			}
		}catch(Exception e){
			log4j.warn(e.getMessage(), e);
		}finally {
			IOUtils.closeQuietly(in);
		}
		return list;
	}
	
	@Override
	public List<PageSource> getModels(Document doc, PageSource page) {
		List<PageSource> list = new ArrayList<>();
		Elements eles = doc.select("#filter_series a");
		for (int i = 0; i < eles.size(); i++) {
			PageSource c = new PageSource();
			c.setUrl(eles.get(i).attr("abs:href"));
			c.setName(eles.get(i).text());
			c.setId(eles.get(i).attr("rrc-event-name"));
			log4j.info(c);
			if(!c.getName().equals("不限")){
				list.add(c);
			}
		}
		return list;
	}

	@Override
	protected String getRowElementSelector() {
		return "#search_list_wrapper li.list-item";
	}


	@Override
	protected PageSource getNextPage(Document doc) {
		Element next = doc.select(".pagination > li").last();
		if(next != null && !next.hasClass("disabled")){
			Element a = next.child(0);
			if("switchright".equals(a.attr("rrc-event-name"))){
				PageSource nextPage = new PageSource();
				nextPage.setUrl(a.attr("abs:href"));
				return nextPage;
			}
		}
		return null;
	}

	@Override
	protected IScrapeEntity eachItem(Element ele, String model, String brand) throws IOException {
		Element a = ele.child(0);
		String carId = a.attr("data-car-id");
		String href = a.attr("abs:href");
		log4j.info("Collect car with ID " + carId + " from " + href);
		if(checkExist(carId, false) == false){
			return null;
		}
		
		String title = a.attr("title");
		Renrenche rrc = new Renrenche();
		rrc.setSourceId(carId);
		rrc.setAdTitle(title);//别克-君越 2013款 2.4L SIDI精英舒适型
		rrc.setAdUrl(href);
		try {
			//build
			int x = title.indexOf("款");
			rrc.setBuild(title.substring(x - 4, x));
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			//buyDate
			String mileageInfo = ele.select(".mileage").text();
			int i = mileageInfo.indexOf("/");
			Date buyDate = DateUtil.string2Date(mileageInfo.substring(0, i).trim());
			rrc.setBuyDate(buyDate);
			//mileage
			int j = mileageInfo.indexOf("万公里");
			int mileage = (int)(Double.parseDouble(mileageInfo.substring(i + 1, j)) * 10000);
			rrc.setMileage(mileage);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			String price = ele.select(".price").get(0).childNode(0).toString();
			rrc.setSoldPrice((int)(Double.parseDouble(price) * 10000));
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		PageSource page = new PageSource();
		page.setName(carId);
		page.setUrl(href);
		try {
			eachDetailPage(page, rrc);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		return rrc;
	}

	private void eachDetailPage(PageSource page, Renrenche rrc) throws Exception {
		Document doc = parseURL(page.getUrl());
		
		try {
			//owner
			Element owner = doc.select(".owner-info").first();
			rrc.setSellerName(owner.child(0).text());
			//  自由职业 | 换车 | 看车地点 北京 海淀 其他
			String[] array = owner.childNode(2).toString().split("\\|");
			rrc.setSellerCareer(array[0].trim());
			rrc.setSellReason(array[1].trim());
			rrc.setSellerAddress(array[2].replace("看车地点", "").trim());
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			//new price
			String newPrice = doc.select(".detail-box .box-installment li").last().text();
			int i = newPrice.indexOf("万");
			rrc.setNewPrice((int)(Double.parseDouble(newPrice.substring(2, i)) * 10000));
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			//emission
			String emission = doc.select(".detail-box .box-list-primary strong.car-summary").get(2).text();
			rrc.setEmission(emission);
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		
		
		try {
			//report
			Element checkDate = doc.select("#report p > span").first();
			String date = checkDate.text().replace("检测时间：", "").trim();
			rrc.setAdDate(DateUtil.string2Date2(date));
			
			Elements tds = doc.select("#report .card-table td");
			rrc.setColor(tds.get(1).text());
			rrc.setInspectionDate(DateUtil.string2Date1(tds.get(3).text()));
			rrc.setInsuranceDate(DateUtil.string2Date1(tds.get(5).text()));
			rrc.setCity(tds.get(9).text());
			rrc.setSoldTimes(Integer.parseInt(tds.get(11).text().replace("次", "")));
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		
		try {
			//parameter
			Elements tab2 = doc.select("#tab-option-2 .node-right");
			Element type = tab2.first();
			if(type != null){
				rrc.setType(type.text());
			}
			
			Element motor = tab2.get(1);
			rrc.setMotor(motor.text());
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
		try {
			Elements motor = doc.select("#tab-option-3 .node-left");
			if(motor != null){
				for (Element ele : motor) {
					String text = ele.text();
					if(text.equals("排量(mL)")){
						rrc.setVolume(Integer.parseInt(ele.nextElementSibling().text()));
					}
					else if(text.equals("最大马力(Ps)")){
						rrc.setHp(Integer.parseInt(ele.nextElementSibling().text()));
						break;
					}
				}
			}
		} catch (Exception e) {
			log4j.error(e.getMessage(), e);
		}
		
	}

	@Override
	public String getSource() {
		return "renrenche";
	}
	
	@Override
	public void finish() {
		Map<Long, String> cars = commonDao.getSoldWithoutTrasactionPrice(getEntityClass());
		log4j.info("Scrape transaction price for: " + cars.size() + " cars");
		for (Entry<Long, String> entry : cars.entrySet()) {
			try {
				Document doc = parseURL(entry.getValue());
				Element priceEle = doc.select(".box-price").first();
				if(priceEle != null){
					if(priceEle.childNodes().size() > 1){
						String text = priceEle.childNode(1).toString();
						int price = (int)(Double.parseDouble(text.substring(1, text.length() - 1)) * 10000);
						commonDao.setTransactionPrice(getEntityClass(), price, entry.getKey());;
					}else{
						log4j.warn("car not sold: " + entry.getKey() + " -->" + entry.getValue());
						commonDao.markUnsold(getEntityClass(), entry.getKey(), startDate);
					}
					
				}else{
					log4j.warn("page not found: " + entry.getKey() + " -->" + entry.getValue());
				}
			} catch (Exception e) {
				log4j.warn("fail to scrape: " + entry.getKey() + " -->" + entry.getValue());
			}
		}
	}

	@Override
	protected Class<? extends IScrapeEntity> getEntityClass() {
		return Renrenche.class;
	}
	

	public static void main(String[] args) throws Exception {
		RenrencheSitemap s = new RenrencheSitemap();
		PageSource p = new PageSource();
		p.setUrl("https://www.renrenche.com/hu/car/1fb7441a3bebe7ac");
		Renrenche r = new Renrenche();
		s.eachDetailPage(p, r);
		
	}
}
